#ifndef PROTOCOL_H_
#define PROTOCOL_H_

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> 

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FLAG 0x7E
#define ESCAPE 0x7D
#define FLAG_SUB 0x5E
#define ESC_SUB 0x5D
#define ADDR_TRANS 0x03
#define ADDR_RECIE 0x01
#define CTRL_SET 0x03
#define CTRL_UA 0x07
#define CTRL_S0 0x00
#define CTRL_S1 0x02
#define CTRL_DISC 0x0B
#define CTRL_RR_S0 0x0A
#define CTRL_RR_S1 0x2A
#define CTRL_REJ_S0 0x01
#define CTRL_REJ_S1 0x21

#define SEP 0x55
#define TRANS 0
#define RECIE 1

enum messageType {_SET,_UA,_DISC,_S0,_S1,_RR_S0,_RR_S1,_REJ_S0,_REJ_S1,_NONE} messageType;

typedef struct{
	unsigned int fileDescriptor; //descritor correspondente à porta serie
	unsigned int status; //transmitter/receptor
} ApplicationLayer;

typedef struct{
	char port[20]; // /dev/ttyS[0/1]
	unsigned int baudRate; //velocidade de transmissao
	unsigned int sequenceNumber; //nº de seq na trama [0,1]
	unsigned int timeout; //tempo q espera ate retransmissao
	unsigned int numRetransmissions; //nº tries em caso de falha
	unsigned int maxSize; //tamanho maximo da trama de informacao
} LinkLayer;

// Commands
typedef struct {
	char flag1;
	char address;
	char control;
	char bcc;
	char flag2;
} SupFrame;

/**
 * handles disconnection in the receiver side
 * @param file descriptor to tty device
 */
void handleReceiverDisconnect(unsigned int fd);
/**
 * used by receiver, state machine for DISC frame
 * @param char to process
 */
void receiveDISC(char c);

/**
 * applies necessary transformations to destuff a stuffed buffer
 * @param buffer: buffer to destuff, start: starting index, 
 * len: ending index and size of stuffed buffer, 
 * disLen: pointer to int where length of destuffed buffer will be saved 
 * @return result
 */
char* destuff(char* buffer, unsigned int start, unsigned int len, unsigned int * disLen);
/**
 * used to propagate changes to link layer struct instance from the app layer to the protocol
 * @param components of link layer
 */
void configureLinkLayer(LinkLayer * l);

/**
 * @param porta: tty device, status: TRANS/RECIE (transmitter/reciever)
 * @return file descriptor to tty device, 0 error
 */
unsigned int llopen(char* porta, unsigned int status);

/**
 * @param fd: file descriptor to tty device, buffer: array to send, length: its length
 * @return: num chars sent, 0 error
 */
unsigned int llwrite(unsigned int fd, char * buffer, unsigned int length);

/**
 * @param: fd: file descriptor to tty device, buffer: array to send, len: its length
 */
void llread(unsigned int fd, char * buffer, unsigned int len);

/**
 * @param: fd: file descriptor to tty device
 * @return: valor positivo se sucesso, ou valor negativo em caso de erro
 */
unsigned int llclose(unsigned int fd);

#endif
